package cn.st4rlight.util.report.check;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;

import cn.st4rlight.util.constant.NumberConstant;
import cn.st4rlight.util.exception.BizAssert;
import cn.st4rlight.util.exception.BizException;
import cn.st4rlight.util.json.ObjectMapperUtil;
import cn.st4rlight.util.page.PageSortReq;
import cn.st4rlight.util.page.PageUtil;
import cn.st4rlight.util.report.dto.TimeCondition;
import cn.st4rlight.util.report.enums.SortOrderType;
import cn.st4rlight.util.report.enums.TimeGroup;
import cn.st4rlight.util.time.DateTimes;
import cn.st4rlight.util.value.NumberUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author st4rlight <st4rlight@163.com>
 * Created on 2025-09-15
 */
@Slf4j
public class ParamBaseChecker {

    /**
     * 限制单次能选择的范围大小（这里实际会多1天）
     * NOTE: 比如限制时间范围不能超过三个月（92天）
     */
    public static void limitOnceTimeRange(TimeCondition timeCondition, int dayLimit) {
        Long lastTime = DateTimes.from(timeCondition.getBeginTime()).plusDays(dayLimit).dayMax().toLong();
        if (lastTime <= timeCondition.getEndTime()) {
            throw BizException.paramInvalid(String.format("单次选择的时间范围不能超过%d天" , dayLimit));
        }
    }

    /**
     * 公共入参 TimeCondition 校验
     * NOTE: 大部分情况下最多只允许选择一年内的时间
     *
     * @param minStartTime 最小允许的开始时间
     * @param minStartErrMsg 最小允许的开始时间错误提示
     */
    public static void checkAndRewriteTime(TimeCondition condition, Long minStartTime, String minStartErrMsg) {
        BizAssert.notNull(condition, "时间条件不能为空");

        // 起始时间校验
        Long beginTime = condition.getBeginTime();
        BizAssert.notNull(beginTime, "起始时间不能为空");
        BizAssert.isTrue(beginTime == 0L || NumberUtil.isPositive(beginTime), "起始时间必须大于0");
        Long endTime = condition.getEndTime();
        BizAssert.isPositive(endTime, "结束时间必须大于0");

        Long oneDayAfter = DateTimes.now().plusDays(1L).dayMin().toLong();
        BizAssert.isTrue(endTime < oneDayAfter, "结束时间不能超过今天");
        BizAssert.isTrue(beginTime >= minStartTime, minStartErrMsg);
        BizAssert.isTrue(beginTime <= endTime, "起始时间不能大于结束时间");

        // 参数时间转换
        LocalDate beginDate = DateTimes.from(beginTime).toLocalDate();
        LocalDate   endDate = DateTimes.from(endTime).toLocalDate();

        // 当前日期，采用同一个变量，防止0点跨天
        LocalDateTime currTime = DateTimes.now().toLocalDateTime();
        LocalDate currDate = currTime.toLocalDate();

        // 时间聚合函数校验
        TimeGroup timeGroup = TimeGroup.of(condition.getGroupType());
        if (TimeGroup.HOUR.equals(timeGroup)) {
            BizAssert.isTrue(beginDate.equals(currDate) && endDate.equals(currDate),
                    "分时数据只能选择当天时间, 请切换查询的统计时间范围");
        }

        // 重写原始参数, 枚举值
        condition.setBeginTime(DateTimes.from(beginTime).dayMin().toLong());
        condition.setGroupType(timeGroup.name());
        if (endDate.equals(currDate)) {
            // 如果结束时间是当天，需要调整为当前时间，底层CK会有缓存，当天数据实时在变
            condition.setEndTime(DateTimes.from(currTime).toLong());
        } else {
            condition.setEndTime(DateTimes.from(endTime).dayMax().toLong());
        }
        log.info("checkAndRewriteTime TimeCondition: {}", ObjectMapperUtil.toJson(condition));
    }

    /**
     * 排序分页参数校验
     */
    public static void checkPageSortReq(PageSortReq pageSortReq, Set<String> allowSortFields) {
        // 分页校验
        PageUtil.checkAndRewritePage(pageSortReq, NumberConstant.NUMBER_100);
        // 排序字段校验
        if (StringUtils.isNotBlank(pageSortReq.getSortField())) {
            BizAssert.isTrue(allowSortFields.contains(pageSortReq.getSortField()), "排序字段不合法");
            pageSortReq.setSortType(SortOrderType.of(pageSortReq.getSortType()).name());
        }
    }
}
